﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace WindowsGame1
{
    class CModel
    {
        public Vector3 Position { get; set; }
        public Vector3 Rotation { get; set; }
        public Vector3 Scale { get; set; }
        public Model Model { get; private set; }
        private Matrix[] modelTransforms;
        private GraphicsDevice graphicsDevice;
        public Texture2D textura;
        public BasicEffect DrawTexture;
        public CModel(Model Model, Vector3 Position, Vector3 Rotation, Vector3 Scale,  GraphicsDevice graphicsDevice)
        {
            this.Model = Model;
            modelTransforms = new Matrix[Model.Bones.Count];
            Model.CopyAbsoluteBoneTransformsTo(modelTransforms);
            this.Position = Position;
            this.Rotation = Rotation;
            this.Scale = Scale;
            this.graphicsDevice = graphicsDevice;
            graphicsDevice.SamplerStates[0] = SamplerState.LinearClamp;
        }

        #region Métodos de Draw

        /// <summary>
        /// Desenha um modelo.
        /// </summary>
        /// <param name="textura">A textura que será aplicada em todas as meshes do modelo</param>
        public void DrawModel(Matrix View, Matrix Projection, Texture2D textura)
        {
            // Calculate the base transformation by combining
            // translation, rotation, and scaling
            Matrix baseWorld = Matrix.CreateScale(Scale) * Matrix.CreateFromYawPitchRoll(Rotation.Y, Rotation.X, Rotation.Z) * Matrix.CreateTranslation(Position);
            foreach (ModelMesh mesh in Model.Meshes) 
            {
                Matrix localWorld = modelTransforms[mesh.ParentBone.Index] * baseWorld;
                foreach (ModelMeshPart meshPart in mesh.MeshParts)
                {
                    BasicEffect effect = (BasicEffect)meshPart.Effect;
                    effect.World = localWorld;
                    effect.View = View;
                    effect.Projection = Projection;
                    effect.EnableDefaultLighting();
                    effect.TextureEnabled = true;
                    effect.Texture = textura;          
                }
                mesh.Draw();
            }
        }
        
        /// <summary>
        /// Desenha um modelo.
        /// </summary>
        public void DrawModel(Matrix View, Matrix Projection)
        {
            // Calculate the base transformation by combining
            // translation, rotation, and scaling
            Matrix baseWorld = Matrix.CreateScale(Scale) * Matrix.CreateFromYawPitchRoll(Rotation.Y, Rotation.X, Rotation.Z) * Matrix.CreateTranslation(Position);
            foreach (ModelMesh mesh in Model.Meshes)
            {
                Matrix localWorld = modelTransforms[mesh.ParentBone.Index] * baseWorld;
                foreach (ModelMeshPart meshPart in mesh.MeshParts)
                {
                    BasicEffect effect = (BasicEffect)meshPart.Effect;
                    effect.World = localWorld;
                    effect.View = View;
                    effect.Projection = Projection;
                    effect.EnableDefaultLighting();
                    effect.TextureEnabled = false;
                }
                mesh.Draw();
            }
        }


        
        /// <summary>
        /// Desenha uma mesh específica
        /// </summary>
        /// <param name="textura">A textura que a mesh terá</param>
        /// <param name="MeshIndex">O índice da mesh a ser desenhada</param>
        public void DrawMesh(Matrix View, Matrix Projection, Texture2D textura, int MeshIndex)
        {
            Matrix baseWorld = Matrix.CreateScale(Scale) * Matrix.CreateFromYawPitchRoll(Rotation.Y, Rotation.X, Rotation.Z) * Matrix.CreateTranslation(Position);

            Matrix localWorld = modelTransforms[Model.Meshes[MeshIndex].ParentBone.Index] * baseWorld;
            foreach (ModelMeshPart meshPart in Model.Meshes[MeshIndex].MeshParts)
            {
                BasicEffect effect = (BasicEffect)meshPart.Effect;
                effect.World = localWorld;
                effect.View = View;
                effect.Projection = Projection;
                effect.EnableDefaultLighting();
                effect.TextureEnabled = true;
                effect.Texture = textura;
            }
            Model.Meshes[MeshIndex].Draw();
        }
        
        /// <summary>
        /// Desenha uma mesh específica
        /// </summary>
        /// <param name="MeshIndex">O índice da mesh a ser desenhada</param>
        public void DrawMesh(Matrix View, Matrix Projection, int MeshIndex)
        {
            Matrix baseWorld = Matrix.CreateScale(Scale) * Matrix.CreateFromYawPitchRoll(Rotation.Y, Rotation.X, Rotation.Z) * Matrix.CreateTranslation(Position);

            Matrix localWorld = modelTransforms[Model.Meshes[MeshIndex].ParentBone.Index] * baseWorld;
            foreach (ModelMeshPart meshPart in Model.Meshes[MeshIndex].MeshParts)
            {
                BasicEffect effect = (BasicEffect)meshPart.Effect;
                effect.World = localWorld;
                effect.View = View;
                effect.Projection = Projection;
                effect.EnableDefaultLighting();
                effect.TextureEnabled = false;
            }
            Model.Meshes[MeshIndex].Draw();
        }
        
        /// <summary>
        /// Desenha uma mesh específica
        /// </summary>
        /// <param name="textura">A textura que a mesh terá</param>
        /// <param name="MeshName">O nome da mesh a ser desenhada</param>
        public void DrawMesh(Matrix View, Matrix Projection, Texture2D textura, string MeshName)
        {
            Matrix baseWorld = Matrix.CreateScale(Scale) * Matrix.CreateFromYawPitchRoll(Rotation.Y, Rotation.X, Rotation.Z) * Matrix.CreateTranslation(Position);
            foreach (ModelMesh mesh in Model.Meshes) // pega todas as meshes (malhas) dentro de determinado modelo. // get all meshes inside a model.
            {
                if (mesh.Name == MeshName)
                {
                    Matrix localWorld = modelTransforms[mesh.ParentBone.Index] * baseWorld;
                    foreach (ModelMeshPart meshPart in mesh.MeshParts)
                    {
                        BasicEffect effect = (BasicEffect)meshPart.Effect;
                        effect.World = localWorld;
                        effect.View = View;
                        effect.Projection = Projection;
                        effect.EnableDefaultLighting();
                        effect.TextureEnabled = true;
                        effect.Texture = textura;
                    }
                    mesh.Draw();
                }
            }
        }
        
        /// <summary>
        /// Desenha uma mesh específica
        /// </summary>
        /// <param name="MeshName">O nome da mesh a ser desenhada</param>
        public void DrawMesh(Matrix View, Matrix Projection, string MeshName)
        {
            Matrix baseWorld = Matrix.CreateScale(Scale) * Matrix.CreateFromYawPitchRoll(Rotation.Y, Rotation.X, Rotation.Z) * Matrix.CreateTranslation(Position);
            foreach (ModelMesh mesh in Model.Meshes) // pega todas as meshes (malhas) dentro de determinado modelo. // get all meshes inside a model.
            {
                if (mesh.Name == MeshName)
                {
                    Matrix localWorld = modelTransforms[mesh.ParentBone.Index] * baseWorld;
                    foreach (ModelMeshPart meshPart in mesh.MeshParts)
                    {
                        BasicEffect effect = (BasicEffect)meshPart.Effect;
                        effect.World = localWorld;
                        effect.View = View;
                        effect.Projection = Projection;
                        effect.EnableDefaultLighting();
                        effect.TextureEnabled = false;
                    }
                    mesh.Draw();
                }
            }
        }



        /// <summary>
        /// Desenha apenas as meshes especificadas
        /// </summary>
        /// <param name="textura">A textura que será usada em cada mesh</param>
        /// <param name="MeshIndexes">Os índices dos meshes que se deseja que sejam exibidos</param>
        public void DrawMeshes(Matrix View, Matrix Projection, Texture2D textura, int[] MeshIndexes)
        {
            Matrix baseWorld = Matrix.CreateScale(Scale) * Matrix.CreateFromYawPitchRoll(Rotation.Y, Rotation.X, Rotation.Z) * Matrix.CreateTranslation(Position);
            for (int n = 0; n < MeshIndexes.Length; n++)
            {
                Matrix localWorld = modelTransforms[Model.Meshes[MeshIndexes[n]].ParentBone.Index] * baseWorld;
                foreach (ModelMeshPart meshPart in Model.Meshes[MeshIndexes[n]].MeshParts)
                {
                    BasicEffect effect = (BasicEffect)meshPart.Effect;
                    effect.World = localWorld;
                    effect.View = View;
                    effect.Projection = Projection;
                    effect.EnableDefaultLighting();
                    effect.TextureEnabled = true;
                    effect.Texture = textura;
                }
                Model.Meshes[MeshIndexes[n]].Draw();
            }

        }

        /// <summary>
        /// Desenha apenas as meshes especificadas
        /// </summary>
        /// <param name="textura">A textura que será usada em cada mesh</param>
        /// <param name="MeshNames">Os nomes dos meshes que se deseja que sejam exibidos</param>
        public void DrawMeshes(Matrix View, Matrix Projection, Texture2D textura, string[] MeshNames)
        {
            Matrix baseWorld = Matrix.CreateScale(Scale) * Matrix.CreateFromYawPitchRoll(Rotation.Y, Rotation.X, Rotation.Z) * Matrix.CreateTranslation(Position);
            foreach (ModelMesh mesh in Model.Meshes)
            {
                foreach (string Name in MeshNames)
                {
                    if (mesh.Name == Name)
                    {
                        Matrix localWorld = modelTransforms[mesh.ParentBone.Index] * baseWorld;
                        foreach (ModelMeshPart meshPart in mesh.MeshParts)
                        {
                            BasicEffect effect = (BasicEffect)meshPart.Effect;
                            effect.World = localWorld;
                            effect.View = View;
                            effect.Projection = Projection;
                            effect.EnableDefaultLighting();
                            effect.Texture = textura;
                            effect.TextureEnabled = true;
                        }
                        mesh.Draw();
                    }
                }
            }

        }


        /// <summary>
        /// Desenha apenas as meshes especificadas
        /// </summary>
        /// <param name="MeshIndexes">Os índices dos meshes que se deseja que sejam exibidos</param>
        public void DrawMeshes(Matrix View, Matrix Projection, int[] MeshIndexes)
        {
            Matrix baseWorld = Matrix.CreateScale(Scale) * Matrix.CreateFromYawPitchRoll(Rotation.Y, Rotation.X, Rotation.Z) * Matrix.CreateTranslation(Position);
            for (int n = 0; n < MeshIndexes.Length; n++)
            {
                Matrix localWorld = modelTransforms[Model.Meshes[MeshIndexes[n]].ParentBone.Index] * baseWorld;
                foreach (ModelMeshPart meshPart in Model.Meshes[MeshIndexes[n]].MeshParts)
                {
                    BasicEffect effect = (BasicEffect)meshPart.Effect;
                    effect.World = localWorld;
                    effect.View = View;
                    effect.Projection = Projection;
                    effect.EnableDefaultLighting();
                    effect.TextureEnabled = true;
                    effect.Texture = textura;
                }
                Model.Meshes[MeshIndexes[n]].Draw();
            }

        }

        /// <summary>
        /// Desenha apenas as meshes especificadas
        /// </summary>
        /// <param name="MeshNames">Os nomes dos meshes que se deseja que sejam exibidos</param>
        public void DrawMeshes(Matrix View, Matrix Projection, string[] MeshNames)
        {
            Matrix baseWorld = Matrix.CreateScale(Scale) * Matrix.CreateFromYawPitchRoll(Rotation.Y, Rotation.X, Rotation.Z) * Matrix.CreateTranslation(Position);
            foreach (ModelMesh mesh in Model.Meshes)
            {
                foreach (string Name in MeshNames)
                {
                    if (mesh.Name == Name)
                    {
                        Matrix localWorld = modelTransforms[mesh.ParentBone.Index] * baseWorld;
                        foreach (ModelMeshPart meshPart in mesh.MeshParts)
                        {
                            BasicEffect effect = (BasicEffect)meshPart.Effect;
                            effect.World = localWorld;
                            effect.View = View;
                            effect.Projection = Projection;
                            effect.EnableDefaultLighting();
                            effect.TextureEnabled = false;
                        }
                        mesh.Draw();
                    }
                }
            }

        }

        #endregion

    }
}
